#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <string>
using namespace std;

// stage 1:线程创建
// question 1:线程的用户级标识符tid到底是多少？与轻量级进程的LWP有何关系？
// new thread tid:140714117687040  new thread LWP:122747
// LWP在内核当中标识一个执行流的唯一性,LWP只在操作系统内部使用;(类似于进程间通信之共享内存的key与shmid之间的关系)
// Linux中线程属于线程库,tid属于pthread库中标识一个执行流的唯一性;tid(用户层)与LWP(内核层)之间必定是一对一的对应关系;

// 将线程的用户层标识转换为16进制
// 线程获取自身的用户级线程标识符tid ----> pthread_self()函数 pthread_t pthread_self(void)
// pthread_create()最后一个参数传参,主线程传参,新线程获取参数;

string ToHex(pthread_t tid)
{
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%lx", tid);
    return buffer;
}

/*void *threadrun(void* args)
{
    string threadname=(char*)(args);
    int cnt = 5;
    while (cnt)
    {
        cout << threadname << " is running,cnt=" << cnt << ",pid:" << getpid() <<"my thread id:"<<ToHex(pthread_self())<< endl;
        sleep(1);
        cnt--;
    }
    return nullptr;
}
int main()
{
    pthread_t tid; // 1.typedef unsigned long int pthread_t;
    pthread_create(&tid, nullptr, threadrun,(void*)"thread -1");
    int cnt = 10;
    while (cnt)
    {
        //主线程可以获取新线程的tid
        cout << "main thread is running,cnt=" << cnt << ",pid:" << getpid()
        <<",new thread tid:"<<ToHex(tid)<<",main thread id:"<<ToHex(pthread_self())<< endl;
        sleep(1);
        cnt--;
    }
    return 0;
}
*/

// stage 2: 线程等待
// question2.用户创建线程会在原生线程库中转换为创建轻量级进程,新线程与主线程哪一个线程先运行？
// 取决于原生线程库的实现,结果不确定,由调度器决定!

// 主线程退出时间比新线程退出时间早即主线程提前退出
// 新线程休眠5s然后退出,主线程休眠1s退出,监控脚本如下:
//  while :; do ps -aL|head -1 && ps -aL|grep testpthread; sleep 1; echo "---------------------------"; done
// 运行结果:主线程退出,新线程也退出
// 结论:主线程退出等同于进程退出,进程是承担分配系统资源的基本实体,进程申请的所有资源全部被释放,所有线程全部退出;使用多线程时主线程应该最后退出;
// 如何保证主线程最后退出&&新线程也需要"wait",否则也会产生内存泄漏问题(类似于父进程率先退出,子进程会变成僵尸进程,进而导致内存泄漏)
// 线程等待----pthread_join()等待指定的thread线程; int pthread_join(pthread_t thread, void **retval);
// 若thread线程没有退出,pthread_join()会让调用该函数的线程进行阻塞式等待
// 若thread线程退出,pthread_join()直接会返回,成功返回0,失败返回错误码
// 新线程具有返回值,当一个线程退出时,主线程需要获取新线程的退出信息,pthread_join()函数的第二个参数是一个输出型参数,获取新线程的退出信息
// retval获取的是新线程的返回值,主线程中定义void* ret=nullptr;//开辟指针变量的空间,用于存放新线程的返回值;
// 新线程的执行情况可以分为三种:1.线程代码执行结束,结果正确  2.线程代码执行结束,结果不正确  3.线程代码没有执行结束,线程出异常

/*void *threadrun(void* args)
{
    string threadname=(char*)(args);
    int cnt = 5;
    while (cnt)
    {
        cout << threadname << " is running,cnt=" << cnt << ",pid:" << getpid() <<"my thread id:"<<ToHex(pthread_self())<< endl;
        sleep(1);
        cnt--;
    }
    //return nullptr;
    return (void*)123;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadrun,(void*)"thread -1");
    //sleep(1);
    void* ret=nullptr;//定义指针变量会开辟4byte/8byte的内存空间,此处开辟8byte的空间
    int n=pthread_join(tid,&ret);
    cout<<"main thread quit,n="<<n<<",main thread get retval: "<<(long long int)ret<<endl;
    return 0;
}
*/

// 新线程的执行情况可以分为三种:1.线程代码执行结束,结果正确  2.线程代码执行结束,结果不正确  3.线程代码没有执行结束,线程出异常
// 新线程的退出码可以决定前两种情形
// 结论:同一个进程内的线程,进程地址空间是共享的;如何证明？
// 如下案例证明进程地址空间中数据区两个线程是共享的&&线程天生可以访问同一块资源,可以实现通信;

/*int g_val = 100; // 定义全局变量g_val
void *threadrun(void *args)
{
    string threadname = (char *)(args);
    int cnt = 5;
    while (cnt)
    {
        printf("new thread g_val: %d, g_val address:%p\n", g_val, &g_val);
        g_val++;
        sleep(1);
        cnt--;
    }
    return (void *)123;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadrun, (void *)"thread -1");
    int cnt = 10;

    while (cnt)
    {
        printf("main thread g_val:%d, g_val address:%p\n", g_val, &g_val);
        sleep(1);
        cnt--;
    }

    void *ret = nullptr;
    int n = pthread_join(tid, &ret);
    cout << "main thread quit,n=" << n << ",main thread get retval: " << (long long int)ret << endl;
    return 0;
}
*/

//线程代码没有执行结束,线程出异常
//主线程死循环,新线程出现野指针异常
//运行结果:主线程和新线程同时退出
//结论1:多线程中,任何一个线程出现异常,都会导致整个进程退出！
//线程是进程内部的一个执行分支,线程出现异常等价于进程出现异常,导致进程退出;
//结论2:多线程代码健壮性不好(多进程之间毫无影响,一个进程崩溃不影响另一个进程,因为进程具有独立性)
//异常信号是发送给进程,进程采取信号捕捉的方式处理信号,handler表在一个进程内部多线程共享！
//线程出现异常,pthread_join()函数进行线程等待为啥没有获取到线程退出的退出信号？
//线程一旦产生信号,整个进程所占据的资源全部被释放,threadrun()函数根本没有机会返回！pthread_join()也没有机会去等待,所以不考虑线程异常的情况！！
//异常应该由父进程进行考量！

/*void *threadrun(void *args)
{
    string threadname = (char *)(args);
    int cnt = 5;
    while (cnt)
    {
        printf("I am new thread,threadname:%s",threadname.c_str());
        sleep(1);
        int* p=nullptr;
        *p=100;
        cnt--;
    }
    return (void *)123;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadrun, (void *)"thread -1");
    int cnt = 10;

    while (true)
    {
        cnt--;
    }
    void *ret = nullptr;
    int n = pthread_join(tid, &ret);

    cout << "main thread quit,n=" << n << ",main thread get retval: " << (long long int)ret << endl;
    return 0;
}
*/

//stage 3: 线程退出
//1.线程函数main()/threadrun()直接结束;return方式
//2.thread_exit()终止线程,exit()终止进程 //void pthread_exit(void *retval);
//3.保证新线程已经启动前提下,主线程使用pthread_cancel()函数 //int pthread_cancel(pthread_t thread);
void *threadrun(void *args)
{
    string threadname = (char *)(args);
    int cnt = 5;
    while (cnt)
    {
        printf("I am new thread,threadname:%s\n",threadname.c_str());
        sleep(1);
        cnt--;
    }
    pthread_exit((void*)123);
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadrun, (void *)"thread -1");

    sleep(2);
    pthread_cancel(tid);
    void *ret = nullptr;
    int n = pthread_join(tid, &ret);

    cout << "main thread quit,n=" << n << ",main thread get retval: " << (long long int)ret << endl;
    return 0;
}